package verifycode

import (
	"fmt"
	"strings"
	"sync"

	"github.com/runningwater/gohub/pkg/app"
	"github.com/runningwater/gohub/pkg/config"
	"github.com/runningwater/gohub/pkg/helpers"
	"github.com/runningwater/gohub/pkg/logger"
	"github.com/runningwater/gohub/pkg/mail"
	"github.com/runningwater/gohub/pkg/sms"
	// "github.com/runningwater/gohub/pkg/sms"
)

type VerifyCode struct {
	Store Store
}

var once sync.Once
var internalVerifyCode *VerifyCode

func NewVerifyCode() *VerifyCode {
	once.Do(func() {
		internalVerifyCode = &VerifyCode{
			Store: NewRedisStore(),
		}
	})
	return internalVerifyCode
}

// SendSMS 发送验证码
// 发送验证码到手机, 调用示例
//
//	verifycode.NewVerifyCode().SendSMS(request.Phone)
func (v *VerifyCode) SendSMS(phone string) bool {
	// 生成验证码
	code := v.generateVerifyCode(phone)

	// 方便本地和 测试环境调试
	if !app.IsProduction() &&
		strings.HasPrefix(phone, config.GetString("verifycode.debug_phone_prefix")) {
		// 测试环境，直接返回成功
		return true
	}
	logger.DebugJSON("验证码", "发送验证码", map[string]string{phone: code})
	// return true
	// 发送验证码
	return sms.NewSMS().Send(phone, sms.Message{
		Template: config.GetString("sms.aliyun.template_code"),
		Data:     map[string]string{"code": code},
	})
}

// SendEmail 发送验证码
// 发送验证码到邮箱, 调用示例
//
//	verifycode.NewVerifyCode().SendEmail(request.Email)
func (v *VerifyCode) SendEmail(email string) error {
	// 生成验证码
	code := v.generateVerifyCode(email)

	// 方便本地和 测试环境调试
	if !app.IsProduction() &&
		strings.HasSuffix(email, config.GetString("verifycode.debug_email_suffix")) {
		return nil
	}

	content := fmt.Sprintf("<p>您的验证码是：%v</p>", code)
	// 发送邮件
	mail.NewMailer().Send(mail.Email{
		From: mail.From{
			Address: config.GetString("mail.from.address"),
			Name:    config.GetString("mail.from.name"),
		},
		To:      []string{email},
		Subject: "Email 验证码",
		HTML:    []byte(content),
	})

	return nil
}

// CheckAnswer 检查验证码是否正确
// key: 手机号 或 Email
func (v *VerifyCode) CheckAnswer(key, answer string) bool {

	logger.DebugJSON("验证码", "检查验证码是否正确", map[string]string{key: answer})
	// 方便本地和 测试环境调试
	if !app.IsProduction() &&
		(strings.HasPrefix(key, config.GetString("verifycode.debug_phone_prefix")) || strings.HasPrefix(key, config.GetString("verifycode.debug_email_prefix"))) {
		return true
	}
	return v.Store.Verify(key, answer, false)
}

// 生成验证码, 并放置于 Redis 中
func (v *VerifyCode) generateVerifyCode(key string) string {
	// 生成随机码
	code := helpers.RandomNumber(config.GetInt("verifycode.code_length"))

	if app.IsLocal() {
		code = config.GetString("verifycode.debug_code")
	}

	logger.DebugJSON("验证码", "生成验证码", map[string]string{key: code})

	// 存储验证码到 Redis
	v.Store.Set(key, code)
	return code
}
